home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1999 January: Mac OS SDK / Dev.CD Jan 99 SDK1.toast / Development Kits / AppleScript / Development Tools / Sample Code / 7Edit 3.1 / Sources / SVAEAccessors.c < prev    next >
Encoding:
Text File  |  1995-11-20  |  29.3 KB  |  1,002 lines  |  [TEXT/CWIE]

  1. // SVAEAccessors.c
  2. //
  3. // 7Edit 3.1d1. Original version by Jon Lansdell and Nigel Humphreys.
  4. // 3.1 updates by Greg Sutton.
  5. // ©Apple Computer Inc 1995, all rights reserved.
  6.  
  7. #include "SVAEAccessors.h"
  8.  
  9. #include <Menus.h>
  10. #include <PLStringFuncs.h>
  11. #include <Scrap.h>
  12. #include <TextEdit.h>
  13. #include <AEObjects.h>
  14. #include <AEPackObject.h>
  15. #include <AERegistry.h>
  16. #include "SVEditGlobals.h"
  17. #include "SVEditUtils.h"
  18. #include "SVEditAEUtils.h"
  19. #include "SVEditWindow.h"
  20. #include "SVEditFile.h"
  21. #include "SVAppleEvents.h"
  22.  
  23. #include "SVToken.h"
  24. #include "SVAETextUtils.h"
  25. #include "SVAEWindowUtils.h"
  26.  
  27.  
  28. #pragma segment AppleEvent
  29.  
  30. // Install accessors that are used when AEResolve is called to convert
  31. // object specifiers into internal representations (tokens).
  32.  
  33. OSErr    InstallAccessors(void)
  34. {
  35.     OSErr    err;
  36.  
  37.     err = AEInstallObjectAccessor(cApplication, typeNull,            NewOSLAccessorProc(ApplicationFromNullAccessor), 0, false);
  38.     err = AEInstallObjectAccessor(cWindow,      typeNull,            NewOSLAccessorProc(WindowFromNullAccessor), 0, false);
  39.     err = AEInstallObjectAccessor(cDocument,    typeNull,            NewOSLAccessorProc(WindowFromNullAccessor), 0, false);
  40.     err = AEInstallObjectAccessor(cProperty,    typeNull,             NewOSLAccessorProc(PropertyFromNullAccessor), 0, false);
  41.  
  42.     err = AEInstallObjectAccessor(cWindow,      typeMyAppl,            NewOSLAccessorProc(WindowFromNullAccessor), 0, false);
  43.     err = AEInstallObjectAccessor(cDocument,    typeMyAppl,            NewOSLAccessorProc(WindowFromNullAccessor), 0, false);
  44.     err = AEInstallObjectAccessor(cProperty,    typeMyAppl,         NewOSLAccessorProc(PropertyFromApplAccessor), 0, false);
  45.  
  46.             // Handle text from a window
  47.             // e.g. some character of last window
  48.     err = AEInstallObjectAccessor(cInsertionPoint,typeMyWndw,        NewOSLAccessorProc(TextElemFromTextAccessor), 0, false);
  49.     err = AEInstallObjectAccessor(cChar,        typeMyWndw,            NewOSLAccessorProc(TextElemFromTextAccessor), 0, false);
  50.     err = AEInstallObjectAccessor(cText,         typeMyWndw,            NewOSLAccessorProc(TextElemFromTextAccessor), 0, false);
  51.     err = AEInstallObjectAccessor(cWord,        typeMyWndw,            NewOSLAccessorProc(TextElemFromTextAccessor), 0, false);
  52.     err = AEInstallObjectAccessor(cParagraph,    typeMyWndw,            NewOSLAccessorProc(TextElemFromTextAccessor), 0, false);
  53.     err = AEInstallObjectAccessor(cProperty,    typeMyWndw,            NewOSLAccessorProc(PropertyFromWndwAccessor), 0, false);
  54.  
  55.             // Handle text items within text items
  56.             // e.g. last word of first paragraph of front window
  57.     err = AEInstallObjectAccessor(cInsertionPoint,typeMyText,        NewOSLAccessorProc(TextElemFromTextAccessor), 0, false);
  58.     err = AEInstallObjectAccessor(cChar,        typeMyText,            NewOSLAccessorProc(TextElemFromTextAccessor), 0, false);
  59.     err = AEInstallObjectAccessor(cText,         typeMyText,            NewOSLAccessorProc(TextElemFromTextAccessor), 0, false);
  60.     err = AEInstallObjectAccessor(cWord,        typeMyText,            NewOSLAccessorProc(TextElemFromTextAccessor), 0, false);
  61.     err = AEInstallObjectAccessor(cParagraph,    typeMyText,            NewOSLAccessorProc(TextElemFromTextAccessor), 0, false);
  62.     err = AEInstallObjectAccessor(cProperty,    typeMyText,            NewOSLAccessorProc(PropertyFromTextAccessor), 0, false);
  63.  
  64.             // Handle text items from lists (of hopefully text items) also
  65.             // e.g. every word of every paragraph of front window
  66.             // or even - every word of every character of every paragraph of front window
  67.     err = AEInstallObjectAccessor(cInsertionPoint,typeAEList,        NewOSLAccessorProc(TextElemFromTextAccessor), 0, false);
  68.     err = AEInstallObjectAccessor(cChar,         typeAEList,            NewOSLAccessorProc(TextElemFromTextAccessor), 0, false);
  69.     err = AEInstallObjectAccessor(cText,         typeAEList,            NewOSLAccessorProc(TextElemFromTextAccessor), 0, false);
  70.     err = AEInstallObjectAccessor(cWord,        typeAEList,            NewOSLAccessorProc(TextElemFromTextAccessor), 0, false);
  71.     err = AEInstallObjectAccessor(cParagraph,    typeAEList,            NewOSLAccessorProc(TextElemFromTextAccessor), 0, false);
  72.     err = AEInstallObjectAccessor(cProperty,    typeAEList,         NewOSLAccessorProc(PropertyFromListAccessor), 0, false);
  73.  
  74.             // This is for 'select insertion point before contents of document 1'
  75.     err = AEInstallObjectAccessor(cInsertionPoint,     typeMyWindowProp,    NewOSLAccessorProc(TextElemFromTextAccessor), 0, false);
  76.  
  77.             // This accessor is for getting properties of window properties
  78.             // e.g. font of contents of window 1
  79.             // Relies on ability to coerce from a window property to text
  80.             // for certain properties.
  81.     err = AEInstallObjectAccessor(cProperty,         typeMyWindowProp,    NewOSLAccessorProc(PropertyFromTextAccessor), 0, false);
  82.  
  83.     return(err);
  84. }
  85.  
  86.  
  87. // Given selectionData of formAbsolutePosition for a window this routine returns
  88. // a WindowToken descriptor for specified window.
  89. //
  90. // e.g.    tell application '7Edit'
  91. //            window 1
  92. //            --first document
  93. //            --some window
  94. //            --every window
  95. //        end tell
  96.  
  97. OSErr    WindowFormAbsolutePosition(const AEDesc    *selectionData, AEDesc* result)
  98. {
  99.     AEDesc    itemDesc = {typeNull, NULL};
  100.     short    windowCount,
  101.             index;
  102.     OSErr    err;
  103.  
  104.     windowCount = CountWindows();
  105.     
  106.     if (! windowCount)
  107.         return(errAEIllegalIndex);
  108.     
  109.     if (typeAbsoluteOrdinal == selectionData->descriptorType)
  110.     {
  111.         switch (*(DescType *)*selectionData->dataHandle)
  112.         {
  113.             case kAEFirst:
  114.                 index = 1;
  115.                 break;
  116.     
  117.             case kAELast:
  118.                 index = windowCount;
  119.                 break;
  120.     
  121.             case kAEMiddle:
  122.                 index = (windowCount + 1) / 2;
  123.                 break;
  124.     
  125.             case kAEAny:
  126.                 index = (Random() % windowCount) + 1;
  127.                 break;
  128.     
  129.             case kAEAll:
  130.                 err = AECreateList(NULL, 0 , false, result);
  131.                 if (noErr != err) goto done;
  132.                 
  133.                 for (index = 1; index <= windowCount; index++)
  134.                 {
  135.                     err = GetDescOfNthWindow(index, &itemDesc);
  136.                     if (noErr != err) goto done;
  137.                     
  138.                     err = AEPutDesc(result, 0, &itemDesc);
  139.                     if (noErr != err) goto done;
  140.                     
  141.                     if (itemDesc.dataHandle)
  142.                         AEDisposeDesc(&itemDesc);
  143.                 }
  144.                 
  145.                 goto done;        // We have created our list descriptor
  146.                 break;            // so we can just tidy up and return.
  147.                 
  148.             default:
  149.                 err = errAETypeError;
  150.         }
  151.     }
  152.     else
  153.         err = GetIntegerFromDescriptor(selectionData, &index);
  154.  
  155.     if (noErr != err) goto done;
  156.     
  157.     if (index < 0)        // Handle negative indexes
  158.         index = windowCount + index + 1;
  159.         
  160.     if (index > windowCount || index <= 0)
  161.         err = errAEIllegalIndex;
  162.     else
  163.         err = GetDescOfNthWindow(index, result);
  164.  
  165. done:    
  166.     if (itemDesc.dataHandle)
  167.         AEDisposeDesc(&itemDesc);
  168.  
  169.     return(err);
  170. } // WindowFormAbsolutePosition
  171.  
  172.  
  173. // Given a formName descriptor in selectionData, this routine returns a
  174. // WindowToken descriptor for the window with that name.
  175. //
  176. // e.g.    tell application '7Edit'
  177. //            document "Untitled"
  178. //        end tell
  179.  
  180. OSErr    WindowFormName(const AEDesc    *selectionData, AEDesc* result)
  181. {
  182.     Str255        name;
  183.     OSErr        err;
  184.     
  185.                 // This tries to coerce it first
  186.     err = GetPStringFromDescriptor(selectionData, name);
  187.     if (noErr != err) goto done;
  188.  
  189.     err = GetDescOfNamedWindow(name, result);
  190.  
  191. done:
  192.     return(err);
  193. }
  194.  
  195.  
  196. // Get a WindowToken descriptor for a window or document object specifier
  197. // from NULL (or the application). Only handles formAbsolutePosition and formName
  198. //
  199. // e.g.    tell application '7Edit'
  200. //            window 1
  201. //            --first document
  202. //            --document "Untitled"
  203. //            --every window
  204. //        end tell
  205.  
  206. pascal OSErr    WindowFromNullAccessor(DescType            wantClass,
  207.                                         const AEDesc    *container,
  208.                                         DescType          containerClass,
  209.                                         DescType        form, 
  210.                                         const AEDesc    *selectionData,
  211.                                         AEDesc            *value,
  212.                                         long            theRefCon)
  213. {
  214. #pragma unused (container,theRefCon)
  215.  
  216.     OSErr       err;
  217.     
  218.         // Can only handle cWindow and cDocument
  219.     if (wantClass != cWindow && wantClass != cDocument)
  220.         return(errAEWrongDataType);
  221.         
  222.         // Can only handle typeNull and typeMyAppl
  223.     if (containerClass != typeNull && containerClass != typeMyAppl)
  224.         return(errAENoSuchObject);
  225.     
  226.     switch (form)
  227.     {
  228.         case formAbsolutePosition:
  229.             err = WindowFormAbsolutePosition(selectionData, value);
  230.             break;
  231.             
  232.         case formName:
  233.             err = WindowFormName(selectionData, value);
  234.             break;
  235.             
  236.         default:
  237.             err = errAEBadTestKey;
  238.     }
  239.             
  240.     return(err);
  241. } // WindowFromNullAccessor
  242.  
  243.  
  244. pascal OSErr   ApplicationFromNullAccessor(DescType        wantClass,
  245.                                             const AEDesc    *container,
  246.                                             DescType        containerClass,
  247.                                             DescType        form, 
  248.                                             const AEDesc    *selectionData,
  249.                                             AEDesc            *value,
  250.                                             long            theRefCon)
  251. {
  252. #pragma unused(container,selectionData,theRefCon)
  253.  
  254.     OSErr    myErr;
  255.     AppToken theApp;
  256.     AEDesc   resultDesc;
  257.     
  258.     value->dataHandle     = nil;
  259.     resultDesc.dataHandle = nil;
  260.     
  261.     /* 
  262.         should only be called with wantClass = cWindow and
  263.         with containerClass = typeNull.
  264.         Currently accept as either formName or formAbsolutePosition
  265.     */
  266.     
  267.     if ((wantClass != cApplication) || (containerClass != typeNull) ||
  268.           !((form == formName) || (form == formAbsolutePosition)))
  269.         return(errAEWrongDataType);
  270.     
  271.     if ((form == formName) || (form == formAbsolutePosition))
  272.     {
  273.         theApp.highLongOfPSN = 0;
  274.         theApp.lowLongOfPSN  = kCurrentProcess;
  275.     }
  276.         
  277.     myErr = AECreateDesc(typeMyAppl, (Ptr)&theApp, sizeof(theApp), value);
  278.             
  279.     return(myErr);
  280. }    /* ApplicationFromNullAccessor */
  281.  
  282.  
  283. // Given a formAbsolutePosition selectionData descriptor and a TextToken from
  284. // which to index from. This routine returns a TextToken descriptor for the
  285. // text specified.
  286. //
  287. // e.g.    tell application '7Edit'
  288. //            first word of window 1    -- window one will be dealt with in
  289. //                                    -- WindowFromNullAccessor().
  290. //            --some character of middle paragraph of last document
  291. //                                    -- container token will be a paragraph
  292. //        end tell
  293.  
  294. OSErr    TextFormAbsolutePosition(TextToken* containerToken, AEDesc* selectionData,
  295.                                                     DescType wantClass, AEDesc* result)
  296. {
  297.     DPtr        docPtr;
  298.     short        elementCount;
  299.     AEDesc        aDesc = {typeNull, NULL};
  300.     long        index;
  301.     OSErr        err;
  302.     
  303.     docPtr = DPtrFromWindowPtr(containerToken->tokenWindow);
  304.  
  305.     if (! docPtr)
  306.     {
  307.         err = errAENoSuchObject;
  308.         goto done;
  309.     }
  310.  
  311.     err = CountTextElements(docPtr->theText, containerToken->tokenOffset,
  312.                                 containerToken->tokenLength, wantClass, &elementCount);
  313.     if (noErr != err) goto done;
  314.  
  315.     if (typeAbsoluteOrdinal == selectionData->descriptorType)
  316.     {
  317.         switch (*(DescType *)*selectionData->dataHandle)
  318.         {
  319.             case kAEFirst:
  320.                 index = 1;
  321.                 break;
  322.     
  323.             case kAELast:
  324.                 index = elementCount;
  325.                 break;
  326.     
  327.             case kAEMiddle:
  328.                 index = (elementCount + 1) / 2;
  329.                 break;
  330.     
  331.             case kAEAny:
  332.                 index = (Random() % elementCount) + 1;
  333.                 break;
  334.     
  335.             case kAEAll:
  336.                 err = AECreateList(NULL, 0 , false, result);
  337.                 
  338.                 for (index = 1; index <= elementCount; index++)
  339.                 {
  340.                     if (noErr == (err = GetDescOfNthTextElement(index, wantClass,
  341.                                                                 containerToken, &aDesc)))
  342.                     {
  343.                         err = AEPutDesc(result, 0, &aDesc);
  344.                         AEDisposeDesc(&aDesc);
  345.                     }
  346.                 }
  347.                 goto done;        // Created our result - clean up and return
  348.                 break;
  349.     
  350.             default:
  351.                 err = errAETypeError;
  352.         }
  353.     }
  354.     else        // Try and get an index out of the descriptor
  355.         err = GetLongIntFromDescriptor(selectionData, &index);
  356.     
  357.     if (noErr != err) goto done;
  358.                     // kAEAll has already created it's list
  359.     err = GetDescOfNthTextElement(index, wantClass,            // Checks for negatives and
  360.                                 containerToken, result);    // out of range.
  361.                                         
  362. done:
  363.     if (aDesc.dataHandle)
  364.         AEDisposeDesc(&aDesc);
  365.  
  366.     return(err);
  367. }
  368.  
  369.  
  370. // Given a TextToken container and a formRange descriptor. This routine
  371. // creates a TextToken descriptor starting at the the beginning of the
  372. // first item in the range and ending at the end of the last item in the range.
  373. //
  374. // e.g.    tell application '7Edit'
  375. //            paragraphs 2 thru 3 of document 1
  376. //        end tell
  377.  
  378. OSErr    TextFormRange(TextToken* containerToken, AEDesc* selectionData,
  379.                                                     DescType wantClass, AEDesc* result)
  380. {
  381. #pragma unused(wantClass)
  382.  
  383.     AEDesc        selectionRecord = {typeNull, NULL};
  384.     TextToken    startToken,
  385.                 stopToken;
  386.     DescType    returnedType;
  387.     Size        actualSize;
  388.     OSErr        err;
  389.  
  390.         // coerce the selection data into an AERecord
  391.     err = AECoerceDesc(selectionData, typeAERecord, &selectionRecord);
  392.     if (noErr != err) goto done;
  393.     
  394.         // get the start object as a text token this will reenter
  395.         // TextElemFromTextAccessor() but as formAbsolutePosition via 
  396.         // our installed coercion handler CoerceObjToAnything()
  397.         // because the keyAERangeStart parameter is actually an object specifier.
  398.     err = AEGetKeyPtr(&selectionRecord, keyAERangeStart, typeMyText,
  399.                             &returnedType, (Ptr)&startToken, sizeof(startToken), &actualSize);
  400.     if (noErr != err) goto done;
  401.     
  402.         // now do the same for the stop object
  403.     err = AEGetKeyPtr(&selectionRecord, keyAERangeStop, typeMyText,
  404.                             &returnedType, (Ptr)&stopToken, sizeof(stopToken), &actualSize);
  405.     if (noErr != err) goto done;
  406.     
  407.     if (containerToken->tokenWindow != startToken.tokenWindow
  408.             || containerToken->tokenWindow != stopToken.tokenWindow)
  409.     {
  410.         err = errAECorruptData;        // or whatever
  411.         goto done;
  412.     }
  413.         
  414.         // Use startToken to create result descriptor
  415.     startToken.tokenLength = stopToken.tokenOffset + stopToken.tokenLength - startToken.tokenOffset;
  416.                                                          
  417.     err = AECreateDesc(typeMyText, (Ptr)&startToken, sizeof(startToken), result);
  418.  
  419. done:
  420.     if (selectionRecord.dataHandle)
  421.         AEDisposeDesc(&selectionRecord);
  422.  
  423.     return(err);
  424. }
  425.  
  426.  
  427. // Given a container TextToken and a formRelativePosition selectionData descriptor
  428. // this routine returns a TextToken descriptor to the reative wantClass object
  429. // specified.
  430. // This routine currently only handles relative positions for a wantClass
  431. // of cInsertionPoint.
  432. //
  433. // e.g.    tell application '7Edit'
  434. //            insertion point after word 5 of document 1
  435. //        end tell
  436.  
  437. OSErr    TextFormRelativePosition(TextToken* containerToken, AEDesc* selectionData,
  438.                                                     DescType wantClass, AEDesc* result)
  439. {
  440.     TextToken    aTextToken;
  441.     DescType     aPosition;
  442.     OSErr        err;
  443.     
  444.     aTextToken.tokenWindow = containerToken->tokenWindow;
  445.  
  446.     switch (wantClass)
  447.     {
  448.         case cInsertionPoint:
  449.             err = GetEnumeratedFromDescriptor(selectionData, &aPosition);
  450.             
  451.             switch (aPosition)
  452.             {
  453.                 case kAEPrevious:
  454.                 case kAEBefore:
  455.                 case kAEBeginning:
  456.                     // No change to offset - just 0 length now
  457.                     // containerToken.tokenOffset = containerToken.tokenOffset;
  458.                     aTextToken.tokenOffset = containerToken->tokenOffset;
  459.                     aTextToken.tokenLength = 0;
  460.                     break;
  461.             
  462.                 case kAENext:
  463.                 case kAEAfter:
  464.                 case kAEEnd:
  465.                     aTextToken.tokenOffset = containerToken->tokenOffset + containerToken->tokenLength;
  466.                     aTextToken.tokenLength = 0;
  467.                     break;
  468.                     
  469.                 default:
  470.                     err = errAEIllegalIndex;
  471.             }
  472.             break;
  473.             
  474.         default:
  475.             err = errAEWrongDataType;    // Could do cChar, cWord… but this is only a sample
  476.     }
  477.     
  478.     if (noErr != err) goto done;
  479.  
  480.     err = AECreateDesc(typeMyText, (Ptr)&aTextToken, sizeof(aTextToken), result);
  481.  
  482. done:
  483.     return(err);
  484. }
  485.  
  486.  
  487. // Tries to create a TextToken descriptor given a container which may
  488. // be a TextToken descriptor or a WindowToken descriptor. A
  489. // selectionData descriptor which can be of formAbsolutePosition,
  490. // formRange or formRelativePosition, and a wantClass which should
  491. // be cInsertionPoint, cChar, cText, cWord or cParagraph.
  492. //
  493. // e.g.    tell application '7Edit'
  494. //            first word of document 1 -- document 1 will go through WindowFromNullAccessor()
  495. //                                     -- which will return a WindowToken descriptor. This
  496. //                                     -- descriptor will then be coerced to a TextToken
  497. //                                     -- descriptor and used as the container.
  498. //        end tell
  499.  
  500. pascal OSErr    TextElemFromTextAccessor(DescType            wantClass,
  501.                                             AEDesc            *container,
  502.                                             DescType        containerClass,
  503.                                             DescType        form,
  504.                                             AEDesc            *selectionData,
  505.                                             AEDesc            *value,
  506.                                             long            theRefCon)
  507. {
  508. #pragma unused(containerClass)
  509.  
  510.     TextToken   containerToken;
  511.     long        index;
  512.     long        itemCount;
  513.     AEDesc        aDesc = {typeNull, NULL},
  514.                 resultDesc = {typeNull, NULL};
  515.     DescType    returnedType;
  516.     Size        actualSize;
  517.     OSErr       myErr;
  518.     
  519.                 // If it's a list then we need to call this accessor for every
  520.                 // item within the list (which could of course be more lists).
  521.     if (typeAEList == container->descriptorType)
  522.     {
  523.         myErr = AECreateList(NULL, 0 , false, value);    // Result will also be a list of items
  524.         if (noErr != myErr) goto done;
  525.         myErr = AECountItems(container, &itemCount);
  526.         if (noErr != myErr) goto done;
  527.  
  528.         for (index = 1; index <= itemCount; index++)    // Do in forward order
  529.         {
  530.             myErr = AEGetNthDesc(container, index, typeWildCard, &returnedType, &aDesc);
  531.  
  532.             if (noErr == myErr)        // Call this function recursively if necessary
  533.                 myErr = TextElemFromTextAccessor(wantClass, &aDesc, returnedType,
  534.                                             form, selectionData, &resultDesc, theRefCon);
  535.             
  536.             if (noErr == myErr)        // Add item to the end of our list
  537.                 myErr = AEPutDesc(value, 0, &resultDesc);
  538.             
  539.             if (aDesc.dataHandle)
  540.                 AEDisposeDesc(&aDesc);
  541.             if (resultDesc.dataHandle)
  542.                 AEDisposeDesc(&resultDesc);
  543.         }
  544.     }
  545.     else
  546.     {                // We have a coercion handler from window to text
  547.         myErr = AECoerceDesc(container, typeMyText, &aDesc);
  548.         if (noErr != myErr) goto done;
  549.  
  550.                 // Get the containing TextToken
  551.         GetRawDataFromDescriptor(&aDesc, (Ptr)&containerToken, sizeof(containerToken), &actualSize);
  552.         
  553.         switch (form)
  554.         {
  555.             case formAbsolutePosition:
  556.                 myErr = TextFormAbsolutePosition(&containerToken, selectionData,
  557.                                                                     wantClass, value);
  558.                 break;                                        
  559.                 
  560.             case formRange:
  561.                 myErr = TextFormRange(&containerToken, selectionData,
  562.                                                             wantClass, value);
  563.                 break;
  564.                 
  565.             case formRelativePosition:
  566.                 myErr = TextFormRelativePosition(&containerToken, selectionData,
  567.                                                                 wantClass, value);
  568.                 break;
  569.                 
  570.             default:
  571.                 myErr = errAEBadKeyForm;
  572.         }
  573.     }
  574.  
  575. done:
  576.     if (aDesc.dataHandle)
  577.         AEDisposeDesc(&aDesc);
  578.         
  579.     return(myErr);
  580. }    // TextElemFromTextAccessor
  581.  
  582.  
  583. // Given a TextToken descriptor as a container convert this into 
  584. // a TextPropToken descriptor for the property.
  585.  
  586. pascal OSErr    PropertyFromTextAccessor(DescType            wantClass,
  587.                                             const AEDesc    *container,
  588.                                             DescType        containerClass,
  589.                                             DescType        form, 
  590.                                             const AEDesc    *selectionData,
  591.                                             AEDesc            *value,
  592.                                             long            theRefCon)
  593. {
  594. #pragma unused (theRefCon, containerClass)
  595.  
  596.     AEDesc            textDesc = {typeNull, NULL},
  597.                     propertyDesc = {typeNull, NULL};
  598.     Size            actualSize;
  599.     TextToken        aTextToken;
  600.     TextPropToken    aTextPropToken;
  601.     DescType        aProperty;
  602.     OSErr            err;
  603.     
  604.     if (cProperty != wantClass || formPropertyID != form)
  605.         return(errAEWrongDataType);
  606.         
  607.                 // Try and coerce to a TextToken descriptor
  608.     err = AECoerceDesc(container, typeMyText, &textDesc);
  609.     if (noErr != err) goto done;
  610.     
  611.                 // Get the TextToken
  612.     GetRawDataFromDescriptor(&textDesc, (Ptr)&aTextToken,
  613.                             sizeof(aTextToken), &actualSize);
  614.             
  615.                 // Make sure the selection data is typeType
  616.     err = AECoerceDesc(selectionData, typeType, &propertyDesc);
  617.     if (noErr != err) goto done;
  618.  
  619.                 // Get the property
  620.     GetRawDataFromDescriptor(&propertyDesc, (Ptr)&aProperty,
  621.                                     sizeof(aProperty),  &actualSize);
  622.             
  623.                 //    Combine the two into single token
  624.     aTextPropToken.tokenTextToken = aTextToken;
  625.     aTextPropToken.tokenProperty  = aProperty;
  626.     
  627.     err = AECreateDesc(typeMyTextProp, (Ptr)&aTextPropToken,
  628.                                 sizeof(aTextPropToken), value);
  629.  
  630. done:        
  631.     if (textDesc.dataHandle)
  632.         AEDisposeDesc(&textDesc);
  633.     if (propertyDesc.dataHandle)
  634.         AEDisposeDesc(&propertyDesc);
  635.         
  636.     return(err);
  637. } // PropertyFromTextAccessor
  638.  
  639.  
  640. // Given a WindowToken descriptor as a container convert this into 
  641. // a WindowPropToken descriptor for the property.
  642.  
  643. pascal OSErr    PropertyFromWndwAccessor(DescType            wantClass,
  644.                                             AEDesc            *container,
  645.                                             DescType        containerClass,
  646.                                             DescType        form, 
  647.                                             AEDesc            *selectionData,
  648.                                             AEDesc            *value,
  649.                                             long            theRefCon)
  650. {
  651. #pragma unused(containerClass)
  652.  
  653.     long                itemCount,
  654.                         index;
  655.     AEDesc                resultDesc = {typeNull, NULL},
  656.                         windowDesc = {typeNull, NULL},
  657.                         propDesc = {typeNull, NULL};
  658.     Size                actualSize;
  659.     DescType            returnedType;
  660.     WindowToken         theWindowToken;
  661.     WindowPropToken     myWindowProp;
  662.     OSErr               err;
  663.     
  664.     if (typeAEList == container->descriptorType)
  665.     {
  666.         err = AECreateList(NULL, 0 , false, value);        // Result will also be a list of items
  667.         if (noErr != err) goto done;
  668.         err = AECountItems(container, &itemCount);
  669.         if (noErr != err) goto done;
  670.     
  671.         for (index = 1; index <= itemCount; index++)    // Do in forward order
  672.         {
  673.             err = AEGetNthDesc(container, index, typeWildCard, &returnedType, &windowDesc);
  674.     
  675.             if (noErr == err)                            // Recursively call this routine
  676.                                                         // - could be another list.
  677.                 err = PropertyFromWndwAccessor(wantClass, &windowDesc, windowDesc.descriptorType,
  678.                                                         form, selectionData, &resultDesc, theRefCon);
  679.             
  680.             if (noErr == err)                            // Add item to the end of our list
  681.                 err = AEPutDesc(value, 0, &resultDesc);
  682.             
  683.             if (windowDesc.dataHandle)
  684.                 AEDisposeDesc(&windowDesc);
  685.             if (resultDesc.dataHandle)
  686.                 AEDisposeDesc(&resultDesc);
  687.         }
  688.     }
  689.     else
  690.     {        // get the window token - it's the container
  691.         
  692.         err = AECoerceDesc(container, typeMyWndw, &windowDesc);
  693.         GetRawDataFromDescriptor(&windowDesc, (Ptr)&theWindowToken,
  694.                                         sizeof(theWindowToken), &actualSize);
  695.                                                             
  696.             // Check the window exists
  697.         
  698.         if (theWindowToken.tokenWindow == NULL)
  699.             err = errAEIllegalIndex;
  700.         else
  701.         {        // get the property - it's in the selection data
  702.             
  703.             err = AECoerceDesc(selectionData, typeType, &propDesc);
  704.             GetRawDataFromDescriptor(&propDesc, (Ptr)&returnedType,
  705.                                             sizeof(returnedType), &actualSize);
  706.             
  707.                 // Combine the two into single token
  708.  
  709.             myWindowProp.tokenWindowToken = theWindowToken;
  710.             myWindowProp.tokenProperty    = returnedType;
  711.             
  712.             err = AECreateDesc(typeMyWindowProp, (Ptr)&myWindowProp,
  713.                                                 sizeof(myWindowProp), value);
  714.         }
  715.     }
  716.     
  717. done:
  718.     if (windowDesc.dataHandle)
  719.         AEDisposeDesc(&windowDesc);
  720.     if (propDesc.dataHandle)
  721.         AEDisposeDesc(&propDesc);
  722.     if (resultDesc.dataHandle)
  723.         AEDisposeDesc(&resultDesc);
  724.         
  725.     return(err);
  726. } // PropertyFromWndwAccessor
  727.  
  728.  
  729. pascal OSErr    PropertyFromNullAccessor(DescType            wantClass,
  730.                                             AEDesc            *container,
  731.                                             DescType        containerClass,
  732.                                             DescType        form, 
  733.                                             AEDesc            *selectionData,
  734.                                             AEDesc            *value,
  735.                                             long            theRefCon)
  736. {
  737. #pragma unused (container, containerClass)
  738.  
  739.     AEDesc        aDesc = {typeNull, NULL};
  740.     OSErr        err;
  741.  
  742.     if ((wantClass != cProperty) || (form != formPropertyID))
  743.         return(errAEWrongDataType);
  744.  
  745.     switch (*(DescType *)*selectionData->dataHandle)
  746.     {
  747.         case pSelection:    // The selection defaults to the front window
  748.                             // selection.
  749.             err = GetDescOfNthWindow(1, &aDesc);    // Disposed of at end
  750.             if (noErr != err) goto done;
  751.             err = PropertyFromWndwAccessor(wantClass, &aDesc, typeMyWndw, form, 
  752.                                                     selectionData, value, theRefCon);
  753.             break;
  754.             
  755.         default:            // Otherwise try an application property - it is fron NULL
  756.             err = PropertyFromApplAccessor(wantClass, &aDesc, typeMyWndw, form, 
  757.                                                     selectionData, value, theRefCon);
  758.     }
  759.     
  760. done:
  761.     if (aDesc.dataHandle)
  762.         AEDisposeDesc(&aDesc);
  763.     
  764.     return(err);
  765. }
  766.  
  767.  
  768. // Convert a list of Token descriptors to a list of Property Token descriptors.
  769. // Only TextTokens and WindowTokens are supported in this version.
  770.  
  771. OSErr    TokenListToPropertyList(AEDesc* tokenList, DescType aProperty, AEDesc* result)
  772. {
  773.     AEDesc                aDesc = {typeNull, NULL},
  774.                         resultDesc = {typeNull, NULL};
  775.     DescType            returnedType;
  776.     long                itemCount,
  777.                         index;
  778.     WindowPropToken        aWindowPropToken;
  779.     TextPropToken        aTextPropToken;
  780.     Size                actualSize;
  781.     OSErr                err;
  782.  
  783.     err = AECreateList(NULL, 0 , false, result);        // Result will also be a list of items
  784.     if (noErr != err) goto done;
  785.     err = AECountItems(tokenList, &itemCount);        // Will return an error if not of type typeAEList
  786.     if (noErr != err) goto done;
  787.  
  788.     for (index = 1; index <= itemCount; index++)    // Do in forward order
  789.     {
  790.         err = AEGetNthDesc(tokenList, index, typeWildCard, &returnedType, &aDesc);
  791.  
  792.         if (noErr == err)                            // Create appropriate property token
  793.             switch (aDesc.descriptorType)
  794.             {
  795.                 case typeMyWndw:
  796.                     GetRawDataFromDescriptor(&aDesc, (Ptr)&aWindowPropToken,
  797.                                                     sizeof(WindowToken), &actualSize);
  798.                     aWindowPropToken.tokenProperty = aProperty;
  799.                     err = AECreateDesc(typeMyWindowProp, (Ptr)&aWindowPropToken,
  800.                                                     sizeof(aWindowPropToken), &resultDesc);
  801.                     break;
  802.                     
  803.                 case typeMyText:
  804.                     GetRawDataFromDescriptor(&aDesc, (Ptr)&aTextPropToken,
  805.                                                     sizeof(TextToken), &actualSize);
  806.                     aTextPropToken.tokenProperty = aProperty;
  807.                     err = AECreateDesc(typeMyTextProp, (Ptr)&aTextPropToken,
  808.                                                     sizeof(aTextPropToken), &resultDesc);
  809.                     break;
  810.                     
  811.                 case typeAEList:                    // Recursive call if a list
  812.                     err = TokenListToPropertyList(&aDesc, aProperty, &resultDesc);
  813.                     break;
  814.                     
  815.                 default:        // May already be a property token
  816.                     err = errAEBadListItem;
  817.             }
  818.         
  819.         if (noErr == err)        // Add item to the end of our list
  820.             err = AEPutDesc(result, 0, &resultDesc);
  821.         
  822.         if (aDesc.dataHandle)
  823.             AEDisposeDesc(&aDesc);
  824.         if (resultDesc.dataHandle)
  825.             AEDisposeDesc(&resultDesc);
  826.             
  827.         err = noErr;            // Try and do all the items we can in the list
  828.     }
  829.             
  830. done:
  831.     return(err);
  832. }
  833.  
  834.  
  835. // Given a container that is a list of Token descriptors, this routine
  836. // returns a list of PropToken descriptors.
  837.  
  838. pascal OSErr    PropertyFromListAccessor(DescType            wantClass,
  839.                                             AEDesc            *container,
  840.                                             DescType        containerClass,
  841.                                             DescType        form, 
  842.                                             AEDesc            *selectionData,
  843.                                             AEDesc            *value,
  844.                                             long            theRefCon)
  845. {
  846. #pragma unused(containerClass, theRefCon)
  847.  
  848.     OSErr        err;
  849.     
  850.     if (wantClass != cProperty && form != formPropertyID)
  851.         return(errAEBadKeyForm);
  852.     
  853.     err = TokenListToPropertyList(container, *(DescType *)*selectionData->dataHandle, value);
  854.  
  855.     return(err);
  856. }
  857.  
  858.  
  859. // Given a AppToken descriptor as a container convert this into 
  860. // a WindowPropToken descriptor for the property.
  861.  
  862. pascal OSErr    PropertyFromApplAccessor(DescType            wantClass,
  863.                                             const AEDesc    *container,
  864.                                             DescType        containerClass,
  865.                                             DescType        form, 
  866.                                             const AEDesc    *selectionData,
  867.                                             AEDesc            *value,
  868.                                             long            theRefCon)
  869. {
  870. #pragma unused (theRefCon, containerClass)
  871.  
  872.     OSErr         myErr;
  873.     OSErr         ignoreErr;
  874.     AppToken      theApplToken;
  875.     DescType      theProperty;
  876.     AEDesc        applDesc;
  877.     AEDesc        propDesc;
  878.     Size          actualSize;
  879.     ApplPropToken myApplProp;
  880.         
  881.     value->dataHandle     = nil;
  882.     applDesc.dataHandle   = nil;
  883.     propDesc.dataHandle   = nil;
  884.     
  885.     if ((wantClass != cProperty) ||
  886.           (form != formPropertyID))
  887.         {
  888.             return(errAEWrongDataType);
  889.         }
  890.     
  891.     /* get the application token - it's the container */
  892.     
  893.     myErr = AECoerceDesc(container, typeMyAppl, &applDesc);
  894.     GetRawDataFromDescriptor(&applDesc,
  895.                                                      (Ptr)&theApplToken,
  896.                                                      sizeof(theApplToken),
  897.                                                      &actualSize);
  898.             
  899.     /* get the property - it's in the selection data */
  900.     
  901.     myErr = AECoerceDesc(selectionData, typeType, &propDesc);
  902.     GetRawDataFromDescriptor(&propDesc,
  903.                                                      (Ptr)&theProperty,
  904.                                                      sizeof(theProperty),
  905.                                                      &actualSize);
  906.     /*
  907.         Combine the two into single token
  908.     */
  909.     myApplProp.tokenApplToken    = theApplToken;
  910.     myApplProp.tokenApplProperty = theProperty;
  911.     
  912.     myErr = AECreateDesc(typeMyApplProp,
  913.                                              (Ptr)&myApplProp,
  914.                                              sizeof(myApplProp),
  915.                                              value);
  916.         
  917.     if (applDesc.dataHandle)
  918.         ignoreErr = AEDisposeDesc(&applDesc);
  919.         
  920.     if (propDesc.dataHandle)
  921.         ignoreErr = AEDisposeDesc(&propDesc);
  922.         
  923.     return(myErr);
  924. } // PropertyFromApplAccessor
  925.  
  926.  
  927. pascal OSErr    PropertyFromWinPropertyAccessor(DescType        wantClass,
  928.                                                 const AEDesc    *container,
  929.                                                 DescType        containerClass,
  930.                                                 DescType        form, 
  931.                                                 const AEDesc    *selectionData,
  932.                                                 AEDesc            *value,
  933.                                                 long            theRefCon)
  934. {
  935. #pragma unused(wantClass, containerClass, form, theRefCon)
  936.  
  937.     OSErr           myErr;
  938.     OSErr           ignoreErr;
  939.     WindowPropToken theWindowPropToken;
  940.     AEDesc          newDesc, propDesc;
  941.     Size            tokenSize;
  942.     DPtr            theDocument;
  943.     TextToken       theTextToken;
  944.     DescType        theProperty;
  945.     Size            actualSize;
  946.     TextPropToken   myTextProp;
  947.     
  948.  
  949.     /* the container is a window property token. Get the token for this */
  950.     /* and check that it is valid to get a property of this property */
  951.     
  952.     myErr = AECoerceDesc(container, typeMyWindowProp, &newDesc);
  953.     
  954.     if (myErr)
  955.      return(myErr);
  956.  
  957.     GetRawDataFromDescriptor(&newDesc,
  958.                                                      (Ptr)&theWindowPropToken,
  959.                                                      sizeof(theWindowPropToken),
  960.                                                      &tokenSize);
  961.                                                      
  962.   /* if the property is pSelection, we then want to convert this to a text token */
  963.     /* and then return a text property token */
  964.     
  965.     if (theWindowPropToken.tokenProperty == pSelection) 
  966.         {
  967.             theDocument = DPtrFromWindowPtr(theWindowPropToken.tokenWindowToken.tokenWindow);
  968.             
  969.             /* build a text token to represent the selection */
  970.             theTextToken.tokenOffset = (**(theDocument->theText)).selStart + 1;
  971.             theTextToken.tokenLength = ((**(theDocument->theText)).selEnd -
  972.                                        (**(theDocument->theText)).selStart) -1;
  973.             theTextToken.tokenWindow = theWindowPropToken.tokenWindowToken.tokenWindow;
  974.             
  975.         
  976.             /* now get the property- it's in the selection data */
  977.             myErr = AECoerceDesc(selectionData, typeType, &propDesc);
  978.             GetRawDataFromDescriptor(&propDesc,
  979.                                                              (Ptr)&theProperty,
  980.                                                              sizeof(theProperty),
  981.                                                              &actualSize);
  982.             
  983.             /* Combine the two into single token */
  984.             myTextProp.tokenTextToken = theTextToken;
  985.             myTextProp.tokenProperty  = theProperty;
  986.     
  987.               myErr = AECreateDesc(typeMyTextProp,(Ptr)&myTextProp,
  988.                                              sizeof(myTextProp),value);
  989.                                              
  990.                                              
  991.           if (propDesc.dataHandle) ignoreErr = AEDisposeDesc(&propDesc);
  992.             if (newDesc.dataHandle)  ignoreErr = AEDisposeDesc(&newDesc);
  993.  
  994.           return myErr;
  995.                                                                                                       
  996.         }
  997.     
  998.     if (newDesc.dataHandle)  ignoreErr = AEDisposeDesc(&newDesc);
  999.     
  1000.     return errAEWrongDataType;
  1001. }
  1002.